package com.example.ploy4j.controller;

import com.example.ploy4j.dto.GitRepositoryConfigDto;
import com.example.ploy4j.dto.ServerConfigDto;
import com.example.ploy4j.dto.DeploymentJobDto;
import com.example.ploy4j.entity.DeploymentJob;
import com.example.ploy4j.entity.DeploymentStatus;
import com.example.ploy4j.entity.GitRepositoryConfig;
import com.example.ploy4j.entity.ServerConfig;
import com.example.ploy4j.mapper.DeploymentJobMapper;
import com.example.ploy4j.repository.DeploymentJobRepository;
import com.example.ploy4j.repository.GitRepositoryConfigRepository;
import com.example.ploy4j.repository.ServerConfigRepository;
import com.example.ploy4j.service.DeploymentService;
import com.example.ploy4j.service.GitRepositoryConfigService;
import com.example.ploy4j.service.ServerConfigService;
import jakarta.persistence.EntityNotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Slf4j
@Controller
@RequestMapping("/deploy")
public class DeploymentController {

    private final DeploymentService deploymentService;
    private final GitRepositoryConfigService gitRepositoryConfigService;
    private final ServerConfigService serverConfigService;
    private final DeploymentJobRepository deploymentJobRepository;
    private final GitRepositoryConfigRepository gitRepoConfigRawRepository;
    private final ServerConfigRepository serverConfigRawRepository;
    private final DeploymentJobMapper deploymentJobMapper;
    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DeploymentController.class);

    public DeploymentController(DeploymentService deploymentService,
                                GitRepositoryConfigService gitRepositoryConfigService,
                                ServerConfigService serverConfigService,
                                DeploymentJobRepository deploymentJobRepository,
                                GitRepositoryConfigRepository gitRepoConfigRawRepository,
                                ServerConfigRepository serverConfigRawRepository,
                                DeploymentJobMapper deploymentJobMapper) {
        this.deploymentService = deploymentService;
        this.gitRepositoryConfigService = gitRepositoryConfigService;
        this.serverConfigService = serverConfigService;
        this.deploymentJobRepository = deploymentJobRepository;
        this.gitRepoConfigRawRepository = gitRepoConfigRawRepository;
        this.serverConfigRawRepository = serverConfigRawRepository;
        this.deploymentJobMapper = deploymentJobMapper;
    }

    private String getCurrentUsername() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.isAuthenticated() && !"anonymousUser".equals(authentication.getName())) {
            return authentication.getName();
        }
        return "system"; // Fallback or anonymous
    }

    @PostMapping("/start")
    @ResponseBody
    public ResponseEntity<?> startDeployment(@RequestParam Long gitRepoConfigId,
                                             @RequestParam Long serverConfigId,
                                             @RequestParam(required = false) String branchName) {
        try {
            GitRepositoryConfig repoConfig = gitRepoConfigRawRepository.findById(gitRepoConfigId)
                    .orElseThrow(() -> new EntityNotFoundException("Git repository config not found with id: " + gitRepoConfigId));
            ServerConfig serverCfg = serverConfigRawRepository.findById(serverConfigId)
                    .orElseThrow(() -> new EntityNotFoundException("Server config not found with id: " + serverConfigId));

            String effectiveBranch = (branchName != null && !branchName.isBlank()) ? branchName : repoConfig.getDefaultBranch();
            if (effectiveBranch == null || effectiveBranch.isBlank()) {
                return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                        .body(Map.of("success", false, "message", "Branch name is not specified and no default branch is set."));
            }

            DeploymentJob newJob = new DeploymentJob();
            newJob.setGitRepositoryConfig(repoConfig);
            newJob.setServerConfig(serverCfg);
            newJob.setBranchToDeploy(effectiveBranch);
            newJob.setStatus(DeploymentStatus.PENDING);
            newJob.setTriggeredBy(getCurrentUsername());
            // createdAt and updatedAt will be set by @CreationTimestamp and @UpdateTimestamp

            DeploymentJob savedJob = deploymentJobRepository.save(newJob);

            deploymentService.startDeploymentPipeline(savedJob.getId());

            return ResponseEntity.ok(Map.of(
                    "success", true,
                    "message", "Deployment job created and started successfully.",
                    "deploymentJobId", savedJob.getId()
            ));
        } catch (EntityNotFoundException e) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND)
                    .body(Map.of("success", false, "message", e.getMessage()));
        } catch (Exception e) {
            // Log the full error for debugging
            logger.error("Failed to start deployment job: ", e); // Assuming logger is available
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(Map.of("success", false, "message", "Failed to start deployment job: " + e.getMessage()));
        }
    }

    // Page to show deployment form and status
    @GetMapping
    public String deploymentPage(Model model) {
        List<GitRepositoryConfigDto> gitRepos = gitRepositoryConfigService.getAllGitRepositoryConfigs();
        List<ServerConfigDto> servers = serverConfigService.getAllServerConfigs();
        model.addAttribute("gitRepos", gitRepos);
        model.addAttribute("servers", servers);
        return "deploy/deployment-form";
    }

    @PostMapping("/trigger-from-form")
    public String triggerDeploymentFromForm(@RequestParam Long gitRepoConfigId,
                                            @RequestParam Long serverConfigId,
                                            @RequestParam(required = false) String branchName,
                                            RedirectAttributes redirectAttributes) {
        try {
            GitRepositoryConfig repoConfig = gitRepoConfigRawRepository.findById(gitRepoConfigId)
                    .orElseThrow(() -> new EntityNotFoundException("Git repository config not found with id: " + gitRepoConfigId));
            ServerConfig serverCfg = serverConfigRawRepository.findById(serverConfigId)
                    .orElseThrow(() -> new EntityNotFoundException("Server config not found with id: " + serverConfigId));

            String effectiveBranch = (branchName != null && !branchName.isBlank()) ? branchName : repoConfig.getDefaultBranch();
            if (effectiveBranch == null || effectiveBranch.isBlank()) {
                redirectAttributes.addFlashAttribute("deploymentError", true);
                redirectAttributes.addFlashAttribute("deploymentMessage", "启动失败: 分支名称未指定且未设置默认分支。");
                return "redirect:/deploy";
            }

            DeploymentJob newJob = new DeploymentJob();
            newJob.setGitRepositoryConfig(repoConfig);
            newJob.setServerConfig(serverCfg);
            newJob.setBranchToDeploy(effectiveBranch);
            newJob.setStatus(DeploymentStatus.PENDING);
            newJob.setTriggeredBy(getCurrentUsername());
            
            DeploymentJob savedJob = deploymentJobRepository.save(newJob);
            deploymentService.startDeploymentPipeline(savedJob.getId());

            redirectAttributes.addFlashAttribute("message", "部署任务 (ID: " + savedJob.getId() + ") 已成功创建并开始执行。");
            redirectAttributes.addAttribute("newJobId", savedJob.getId());

            return "redirect:/deploy/jobs";

        } catch (EntityNotFoundException e) {
            redirectAttributes.addFlashAttribute("deploymentError", true);
            redirectAttributes.addFlashAttribute("deploymentMessage", "启动失败: " + e.getMessage());
            return "redirect:/deploy";
        } catch (Exception e) {
            logger.error("Failed to trigger deployment from form: ", e);
            redirectAttributes.addFlashAttribute("deploymentError", true);
            redirectAttributes.addFlashAttribute("deploymentMessage", "启动部署任务时发生内部错误: " + e.getMessage());
            return "redirect:/deploy";
        }
    }

    // Page to display deployment jobs
    @GetMapping("/jobs")
    public String listDeploymentJobsPage(Model model, @RequestParam(name = "newJobId", required = false) Long newJobId) {
        if (newJobId != null) {
            model.addAttribute("newJobId", newJobId);
        }
        return "deploy/deployment-jobs";
    }

    // API Endpoints for Deployment Jobs
    @GetMapping("/api/deployment-jobs")
    @ResponseBody
    public ResponseEntity<List<DeploymentJobDto>> getAllDeploymentJobs(@RequestParam(required = false) Long gitRepositoryConfigId) {
        List<DeploymentJob> jobs;
        if (gitRepositoryConfigId != null) {
            logger.info("Fetching deployment jobs for gitRepositoryConfigId: {}", gitRepositoryConfigId);
            jobs = deploymentJobRepository.findByGitRepositoryConfigIdOrderByCreatedAtDesc(gitRepositoryConfigId);
        } else {
            logger.info("Fetching all deployment jobs.");
            jobs = deploymentJobRepository.findAllByOrderByCreatedAtDesc();
        }
        List<DeploymentJobDto> jobDtos = deploymentJobMapper.toDtoList(jobs);
        return ResponseEntity.ok(jobDtos);
    }

    @GetMapping("/api/deployment-jobs/{id}")
    @ResponseBody
    public ResponseEntity<DeploymentJobDto> getDeploymentJobById(@PathVariable Long id) {
        log.info("Fetching deployment job with ID: {}", id);
        Optional<DeploymentJob> jobOptional = deploymentJobRepository.findById(id);
        log.info("Job found: {}", jobOptional.isPresent());
        if (jobOptional.isEmpty()) {
            return ResponseEntity.notFound().build();
        }
        DeploymentJobDto jobDto = deploymentJobMapper.toDto(jobOptional.get());
        return ResponseEntity.ok(jobDto);
    }
} 